<?php

class Damages_Auth implements Zend_Auth_Adapter_Interface {

  const PERMISSION_ADMIN = 'ADM';
  const PERMISSION_LS = 'LS';
  const PERMISSION_OL = 'OL';
  const PERMISSION_SD = 'SD';

  /**
   * 
   * @var Damages_AuthData_ILoginData
   */
  protected $_loginData = null;

  /**
   * 
   * @var string
   */
  protected $_namespace = null;

  /**
   *
   * @var DamagesUsers
   */
  private $user = null;

  /**
   *
   * @var Zend_Session_Namespace
   */
  private $session = null;

  /**
   *
   * @var DamagesSessions
   */
  private $dbSession = null;

  /**
   *
   * @var Damages_Methods_Data_App
   */
  private $app = null;
  private $processTypesPermissions;
  private $filtersPermissions;
  private $fieldsPermissions;

  /**
   *
   * @var Damages_Auth
   */
  static private $_instance = null;

  public static function getInstance() {
    if (self::$_instance === null) {
      self::$_instance = new self();
      self::$_instance->init();
    }
    return self::$_instance;
  }

  public function setLogin($login) {
    $this->_login = $login;
    return $this;
  }

  /**
   * 
   * @param string $email
   * @param string $password
   * @return \Zend_Auth_Result
   */
  public function authenticate() {
    $this->session->auth = false;
    if (!$this->_loginData instanceof Damages_AuthData_ILoginData)
      return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, null, array('No credentials initiated'));
    $this->user = $this->_loginData->getUser();

    if (!$this->user instanceof DamagesUsers) {
      return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, $this->_loginData->getId(), array('Invalid email or password'));
    }
    $this->initDbSession();
    $this->session->auth = true;
    $this->session->userId = $this->user->getId();
    $this->session->sessionId = $this->dbSession->getSessionId();

    return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $this->_loginData->getId());
  }

  public function init() {
    $this->_namespace = Damages_Config::getInstance()->session->namespace;
    $this->session = new Zend_Session_Namespace($this->_namespace);
    if ($this->session->sessionId === null) {
      $this->session->auth = false;
      $this->session->userId = null;
      $this->session->sessionId = null;
    } else {
      if ($this->initDbSession($this->session->sessionId)) {
        $this->session->auth = true;
        $this->session->userId = $this->user->getId();
      } else {
        $this->session->auth = false;
        $this->session->userId = null;
        $this->session->sessionId = null;
      }
    }
  }

  public function logout() {
    $session = new Zend_Session_Namespace($this->_namespace);
    $session->auth = false;
    $session->userId = null;
    $session->sessionId = null;
    $this->user = null;
  }

  public function getUser() {
    return $this->user;
  }

  public function isAuth() {
    $session = new Zend_Session_Namespace($this->_namespace);
    return $session->auth;
  }

  private function initDbSession($sessionId = null) {
    if ($sessionId === null) {
      $this->dbSession = new DamagesSessions();
      $this->dbSession->setSessionId($this->generateSid());
    } else {
      $dt = new DateTime();
      $this->dbSession = DamagesSessionsQuery::create()
                      ->useUsersQuery()
                      ->joinPermissions()
                      ->endUse()
                      ->filterBySessionId($sessionId)
                      ->filterByActiveTo($dt, Criteria::GREATER_THAN)
                      ->with('Users')
                      ->with('Permissions')
                      ->find()->getFirst();
      if (!$this->dbSession instanceof DamagesSessions)
        return false;
      $this->user = $this->dbSession->getUsers();
    }
    $this->dbSession->setUserId($this->user->getId());
    $activeTo = new DateTime();
    $activeTo->add(new DateInterval('PT' . Damages_Config::getInstance()->dbSession->valid_for . 'S'));
    $this->dbSession->setActiveTo($activeTo);
    $this->dbSession->save();
    return true;
  }

  private function generateSid() {
    mt_srand($this->make_seed());
    $val = microtime(true) + mt_rand(0, 100000);
    $sid = hash('sha256', $val);
    $result = DamagesSessionsQuery::create()->findOneBySessionId($sid);
    $sid = (($result instanceof DamagesSessions) ? $this->generateSid() : $sid );
    return $sid;
  }

  private function make_seed() {
    list($usec, $sec) = explode(' ', microtime());
    return (float) $sec + ((float) $usec * 100000);
  }

  /**
   * 
   * @return Zend_Session_Namespace
   */
  public function getSession() {
    return $this->session;
  }

  /**
   * 
   * @return DamagesSessions
   */
  public function getDbSession() {
    return $this->dbSession;
  }

  /**
   * 
   * @param type $loginData
   * @return \Damages_Auth
   */
  public function setLoginData($loginData) {
    $this->_loginData = $loginData;
    return $this;
  }

  /**
   * 
   * @param Damages_Methods_Data_App $app
   */
  public function setApp($app) {
    $this->app = $app;
  }

  /**
   * 
   * @param string/array $type
   * @return boolean
   */
  public function checkPermission($type) {
    if (!$this->user)
      return false;
    if (is_array($type)) {
      if (in_array($this->user->getPermissions()->getCode(), $type))
        return true;
    } else if ($this->user->getPermissions()->getCode() == $type)
      return true;
    return false;
  }

  public function setUserPermissions() {
    $this->setProcessPermissions();
    $this->setFiltersPermisions();
    $this->setFieldsPermisions();
  }

  private function setProcessPermissions() {
    $processTypesPermissions = DamagesProcessTypePermissionsQuery::create()
            ->useProcessTypesQuery()
            ->useProcessTypeActionsQuery()
            ->joinActions()
            ->joinProcessTypeActionsPermissions()
            ->endUse()
            ->endUse()
            ->addJoinCondition('ProcessTypeActionsPermissions', sprintf('%s = %s', DamagesProcessTypeActionsPermissionsPeer::PERMISSION_ID, DamagesProcessTypePermissionsPeer::PERMISSION_ID))
            ->filterByPermissionId($this->user->getPermissionId())
            ->with('ProcessTypes')
            ->with('ProcessTypeActions')
            ->with('Actions')
            ->find();
    $this->processTypesPermissions = $processTypesPermissions;
  }

  private function setFiltersPermisions() {
    $filtersPermissions = DamagesPermissionListFiltersQuery::create()
            ->useListFiltersQuery()
            ->orderByDbOrder()
            ->endUse()
            ->filterByPermissionId($this->user->getPermissionId())
            ->with('ListFilters')
            ->find();
    $this->filtersPermissions = $filtersPermissions;
  }

  private function setFieldsPermisions() {
    $fieldsPermissions = DamagesPermissionListFieldsQuery::create()
            ->useListFieldsQuery()
            ->orderByDbOrder()
            ->endUse()
            ->filterByPermissionId($this->user->getPermissionId())
            ->with('ListFields')
            ->find();
    $this->fieldsPermissions = $fieldsPermissions;
  }

  public function getProcessTypesPermissions() {
    if ($this->processTypesPermissions === null)
      $this->setUserPermissions();
    return $this->processTypesPermissions;
  }

  public function getFiltersPermissions() {
    if ($this->filtersPermissions === null)
      $this->setUserPermissions();
    return $this->filtersPermissions;
  }

  public function getFieldsPermissions() {
    if ($this->fieldsPermissions === null)
      $this->setUserPermissions();
    return $this->fieldsPermissions;
  }

  /**
   * 
   * @param int $filterId
   * @return DamagesListFilters
   */
  public function getUserFilter($filterId) {
    foreach ($this->filtersPermissions as $filterPermission) {
      if ($filterPermission->getListFilterId() == $filterId)
        return $filterPermission->getListFilters();
    }
    return null;
  }

  public function changePassword($newPassword) {
    $hashP = Damages_AuthData_Email::crypt($newPassword);
    $this->user->setPassword($hashP);
    $this->user->setForcePasswordChange(0);
    $this->user->save();
  }

}